package com.tuju.jetpackfirstdemo.ui.opengl2;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.opengl.EGLConfig;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.os.Bundle;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.view.MotionEvent;

import javax.microedition.khronos.opengles.GL10;

public class OpenGLES20Activity extends AppCompatActivity {

    private MyGLSurfaceView mGLView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mGLView = new MyGLSurfaceView(this);

        // 含义： 仅在你的绘制数据发生变化时才在视图中进行绘制操作：
        // 如果选用这一配置选项，那么除非调用了requestRender()，否则GLSurfaceView不会被重新绘制，这样做可以让应用的性能及效率得到提高。
        // Render the view only when there is a change in the drawing data
         mGLView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);

        setContentView(mGLView);
    }


    //继承GLSurfaceView来捕捉触控事件
    class MyGLSurfaceView extends GLSurfaceView {

        private final MyGLRenderer mRenderer;

        public MyGLSurfaceView(Context context) {
            super(context);
            // Create an OpenGL ES 2.0 context
            // 需要在GLSurfaceView中设置OpenGL的版本：否则会报类似错误 glDrawArrays is called with VERTEX_ARRAY client state disabled!
            setEGLContextClientVersion(2);

            mRenderer = new MyGLRenderer();

            // Set the Renderer for drawing on the GLSurfaceView
            setRenderer(mRenderer);
        }

        // 处理旋转手势 touch scale factor
        private final float TOUCH_SCALE_FACTOR = 180.0f / 320;
        private float mPreviousX;
        private float mPreviousY;

        @Override
        public boolean onTouchEvent(MotionEvent e) {
            // MotionEvent通过触摸屏报告输入详细信息
            // 和其他输入控件。在这种情况下，你只是
            // 对触摸位置发生变化的事件感兴趣。

            float x = e.getX();
            float y = e.getY();

            switch (e.getAction()) {
                case MotionEvent.ACTION_MOVE:

                    float dx = x - mPreviousX;
                    float dy = y - mPreviousY;

                    // reverse direction of rotation above the mid-line
                    if (y > getHeight() / 2) {
                        dx = dx * -1 ;
                    }

                    // reverse direction of rotation to left of the mid-line
                    if (x < getWidth() / 2) {
                        dy = dy * -1 ;
                    }

                    mRenderer.setAngle(
                            mRenderer.getAngle() +
                                    ((dx + dy) * TOUCH_SCALE_FACTOR));
                    requestRender();
            }

            mPreviousX = x;
            mPreviousY = y;
            return true;
        }

    }

    /**
     * 集成GLSurfaceView.Renderer通常被称为渲染器
     */
    public static class MyGLRenderer implements GLSurfaceView.Renderer {
        private Triangle mTriangle;
        private Square mSquare;

        // 由于渲染器代码运行在一个独立的线程中（非主UI线程），我们必须同时将该变量声明为volatile。
        public volatile float mAngle;

        public float getAngle() {
            return mAngle;
        }

        public void setAngle(float angle) {
            mAngle = angle;
        }

        // 调用一次，用来配置View的OpenGL ES环境。
        @Override
        public void onSurfaceCreated(GL10 gl, javax.microedition.khronos.egl.EGLConfig config) {
            // Set the background frame color
            GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

            mTriangle = new Triangle();
            mSquare = new Square();
        }

        // 每次重新绘制View时被调用。
        public void onDrawFrame(GL10 unused) {
            GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);

            //增加相机与投影
            // 设置相机位置（视图矩阵）
            Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

            // 计算投影和视图转换
            Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);

            // 绘制三角形
//            mTriangle.draw(mMVPMatrix);

            //旋转
            // 重绘背景色
            float[] scratch = new float[16];

            // 为三角形创建旋转变换
//            long time = SystemClock.uptimeMillis() % 4000L;
//            float angle = 0.090f * ((int) time);
//            Matrix.setRotateM(mRotationMatrix, 0, angle, 0, 0, -1.0f);//自動旋轉

            Matrix.setRotateM(mRotationMatrix, 0, mAngle, 0, 0, -1.0f);//根據傳入角度旋轉

            // 将旋转矩阵与投影和相机视图结合
            // 请注意，mMVPMatrix因子*必须按顺序排在第一*
            // 使矩阵乘法乘积正确。
            Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);

            // 绘制三角形
            mTriangle.draw(scratch);
        }

        // 如果View的几何形态发生变化时会被调用，例如当设备的屏幕方向发生改变时。
        public void onSurfaceChanged(GL10 unused, int width, int height) {
            GLES20.glViewport(0, 0, width, height);

            float ratio = (float) width / height;
            // this projection matrix is applied to object coordinates
            Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
        }

        //定义一个投影 onSurfaceChanged
        // 一个投影变换一般仅当OpenGL View的比例在渲染器的onSurfaceChanged()方法中建立或发生变化时才被计算。
        // mMVPMatrix is an abbreviation for "Model View Projection Matrix"
        private final float[] mMVPMatrix = new float[16];
        private final float[] mProjectionMatrix = new float[16];
        private final float[] mViewMatrix = new float[16];

        //旋转一个形状
        private float[] mRotationMatrix = new float[16];

        //编译着色器代码的辅助方法
        public static int loadShader(int type, String shaderCode) {
            // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
            // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
            int shader = GLES20.glCreateShader(type);

            // add the source code to the shader and compile it
            GLES20.glShaderSource(shader, shaderCode);
            GLES20.glCompileShader(shader);

            return shader;
        }
    }
}
